package solver;

import ilog.concert.IloException;
import ilog.concert.IloNumVar;
import ilog.cplex.IloCplex;

import java.util.Hashtable;

import tools.Vector;
import uncertainty.UncertaintySet;

/**
 * @class VariableMapping
 * 
 * This class represents a abstract mapping for the variables used to build up 
 * the diferrent problems in this code.
 * 
 * @author Marcio Costa Santos
 */
public abstract class VariableMapping {

	/** The delay coeficient. */
	protected int k;
	/** The number of periods. */
	protected int n;
	/** The final number of variables.*/
	protected int numvar;
	
	/**
	 * @innerclass StrucRecXiT
	 * 
	 * Inner class used to represent the indices of a variable, it is a 
	 * ordered pair of a natural number and a element, vector, belloging to
	 * the uncertainty set.
	 * 
	 * */
	protected class StrucRecXiT implements Comparable<StrucRecXiT>{

		/** The period referenced by this object.*/
		private int t;
		/** The demand referenced by this object. */
		private Vector<Double> vec;

		/**
		 * Simple Constructor
		 * */
		public StrucRecXiT(Vector<Double> projection, int t2) {
			vec = projection;
			t = t2;
		}

		@Override
		/** 
		 * @method compareTo
		 * 
		 * @param o
		 * 
		 * @return
		 * */
		public int compareTo(StrucRecXiT o) {
			if(t < o.t) return 1;
			else if (t > o.t) return -1;
			else return vec.compareTo(o.vec);
		}
		
		/** 
		 * @method equals
		 * 
		 * @param o2
		 * 
		 * @return
		 * */
		public boolean equals(Object o2){
			StrucRecXiT o = (StrucRecXiT)o2;
			if(t != o.t) return false;
			else return vec.compareTo(o.vec) == 0;
		}
		
		/** 
		 * @method hashcode
		 * 
		 * @return
		 * */
		public int hashCode(){
			return t + vec.sum(vec.getDim()).intValue();
		}
		
	}
	
	/** Mapping that stores all the references to the variables in function of 
	 * their indexes represent by a object of type StrucRecXiT*/
	protected Hashtable<StrucRecXiT, IloNumVar[]> map;
	
	/**
	 * @Constructor
	 * 
	 * @param dim
	 * @param k
	 * */
	public VariableMapping(int dim, int k) {
		this.n = dim;
		this.k = k;
		map = new Hashtable<VariableMapping.StrucRecXiT, IloNumVar[]>();
	}
	
	/**
	 * @method initialize
	 * 
	 * @param UncertaintySet us
	 * @param  Ilocplex cplex
	 * */
	public abstract void initialize(UncertaintySet us, IloCplex cplex) throws IloException;
	
	/**
	 * @method getNumVar
	 * 
	 * */
	public int getNumVar(){
		return numvar;
	}
	
	/**
	 * @method getVariableFor
	 * 
	 * @param vector
	 * @param t
	 * 
	 * @return 
	 * */
	public IloNumVar[] getVariableFor(Vector<Double> vector, int t){
		return map.get(new StrucRecXiT(vector.getProjection(t-k), t));
	}
	
	/**
	 * @method finalize
	 * 
	 * */
	public void finalize(){
		map = null;
		System.gc();
	}
}
